#ifndef cathlibcpp_ptypeinfo_H
#define cathlibcpp_ptypeinfo_H

// File:       ptypeinfo.h
// Author:     (c) Miles Sabin, 1996
// Purpose:    fake RTTI for Acorn CFront
//             private header for inclusion from typeinfo.h and exception.h


#ifndef cathlibcpp_config_H
#include "config.h"
#endif


#ifdef BUILTIN_RTTI

#define PTR_typeid   typeid
#define REF_typeid   typeid
#define TYPE_typeid  typeid

#define PTR_dynamic_cast(T, p) dynamic_cast<T*>(p)
#define REF_dynamic_cast(T, r) dynamic_cast<T&>(r)

#define RTTI_SCAFFOLDING_DECL

#define RTTI_SCAFFOLDING_DEFN_0(T)
#define RTTI_SCAFFOLDING_DEFN_1(T, B1)
#define RTTI_SCAFFOLDING_DEFN_2(T, B1, B2)
#define RTTI_SCAFFOLDING_DEFN_3(T, B1, B2, B3)
#define RTTI_SCAFFOLDING_DEFN_4(T, B1, B2, B3, B4)

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_0(A, T)
#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_1(A, T, B1)
#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_2(A, T, B1, B2)
#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_3(A, T, B1, B2, B3)
#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_4(A, T, B1, B2, B3, B4)

#else // !BUILTIN_RTTI

#define PTR_typeid(p)          ((p) == 0 ? RTTI_bad_typeid() : (p)->RTTI_get_type_info())
#define REF_typeid(r)          ((r).RTTI_get_type_info())
#define TYPE_typeid(T)         ((type_info const&)T::RTTI_type_info)

#define PTR_dynamic_cast(T, p) ((T*)((p) == 0 ? 0 : (p)->RTTI_dynamic_cast(TYPE_typeid(T))))
#define REF_dynamic_cast(T, r) ((T&)RTTI_check_bad_cast((r).RTTI_dynamic_cast(TYPE_typeid(T))))

extern void* RTTI_bad_typeid();
extern void* RTTI_check_bad_cast(void* p);

// Macro to declare RTTI scaffolding in class declaration
// Usage:
//
//  class Foo
//  {
//    public:
//      // etc...
//
//      RTTI_SCAFFOLDING_DECL
//
//    private:
//      // etc...
//  };

#define RTTI_SCAFFOLDING_DECL                                                       \
  static type_info RTTI_type_info;                                                  \
  virtual type_info const& RTTI_get_type_info() const;                              \
  virtual void* RTTI_dynamic_cast(type_info const&) const;



// Macros to define RTTI scaffolding in non-template class definition (.c++) files
// Usage:
//
// RTTI_SCAFFOLDING_DEFN_0(Foo)                             // for classes with no bases
// RTTI_SCAFFOLDING_DEFN_1(Foo, Base1)                      // for classes with 1 base
// RTTI_SCAFFOLDING_DEFN_2(Foo, Base1, Base2)               // for classes with 2 bases
// RTTI_SCAFFOLDING_DEFN_3(Foo, Base1, Base2, Base3)        // for classes with 3 bases
// RTTI_SCAFFOLDING_DEFN_4(Foo, Base1, Base2, Base3, Base4) // for classes with 4 bases

#define RTTI_SCAFFOLDING_DEFN_0(T)                                                  \
  type_info T::RTTI_type_info(#T);                                                  \
  type_info const& T::RTTI_get_type_info() const                                    \
    { return RTTI_type_info; }                                                      \
  void* T::RTTI_dynamic_cast(type_info const& info) const                           \
    {                                                                               \
      return &info == &RTTI_type_info ? (void*)this : 0;                            \
    }

#define RTTI_SCAFFOLDING_DEFN_1(T, B1)                                              \
  type_info T::RTTI_type_info(#T);                                                  \
  type_info const& T::RTTI_get_type_info() const                                    \
    { return RTTI_type_info; }                                                      \
  void* T::RTTI_dynamic_cast(type_info const& info) const                           \
    {                                                                               \
      return &info == &RTTI_type_info ? (void*)this : B1::RTTI_dynamic_cast(info);  \
    }

#define RTTI_SCAFFOLDING_DEFN_2(T, B1, B2)                                          \
  type_info T::RTTI_type_info(#T);                                                  \
  type_info const& T::RTTI_get_type_info() const                                    \
    { return RTTI_type_info; }                                                      \
  void* T::RTTI_dynamic_cast(type_info const& info) const                           \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

#define RTTI_SCAFFOLDING_DEFN_3(T, B1, B2, B3)                                      \
  type_info T::RTTI_type_info(#T);                                                  \
  type_info const& T::RTTI_get_type_info() const                                    \
    { return RTTI_type_info; }                                                      \
  void* T::RTTI_dynamic_cast(type_info const& info) const                           \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B3::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

#define RTTI_SCAFFOLDING_DEFN_4(T, B1, B2, B3, B4)                                  \
  type_info T::RTTI_type_info(#T);                                                  \
  type_info const& T::RTTI_get_type_info() const                                    \
    { return RTTI_type_info; }                                                      \
  void* T::RTTI_dynamic_cast(type_info const& info) const                           \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B3::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B4::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

// Macros to define RTTI scaffolding in template class definition (.c++) files
// Usage:
//
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_0(/* template arg list */, Foo)                             // for classes with no bases
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_1(/* template arg list */, Foo, Base1)                      // for classes with 1 base
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_2(/* template arg list */, Foo, Base1, Base2)               // for classes with 2 bases
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_3(/* template arg list */, Foo, Base1, Base2, Base3)        // for classes with 3 bases
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_4(/* template arg list */, Foo, Base1, Base2, Base3, Base4) // for classes with 4 bases
//
// Where /* template arg list */ is replaced with the arg list for class template Foo,
// with any embedded ','s replaced by '_'s, eg,
//
// template<class T, int i>
// class Foo {};
//
// RTTI_TEMPLATE_SCAFFOLDING_DEFN_0(<class T _ int i>, Foo)
//

#undef _
#define _ ,

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_0(A, T)                                      \
  template A                                                                        \
  type_info T A::RTTI_type_info(#T #A);                                             \
  template A                                                                        \
  type_info const& T A::RTTI_get_type_info() const                                  \
    { return RTTI_type_info; }                                                      \
  template A                                                                        \
  void* T A::RTTI_dynamic_cast(type_info const& info) const                         \
    {                                                                               \
      return &info == &RTTI_type_info ? (void*)this : 0;                            \
    }

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_1(A, T, B1)                                  \
  template A                                                                        \
  type_info T A::RTTI_type_info(#T #A);                                             \
  template A                                                                        \
  type_info const& T A::RTTI_get_type_info() const                                  \
    { return RTTI_type_info; }                                                      \
  template A                                                                        \
  void* T A::RTTI_dynamic_cast(type_info const& info) const                         \
    {                                                                               \
      return &info == &RTTI_type_info ? (void*)this : B1::RTTI_dynamic_cast(info);  \
    }

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_2(A, T, B1, B2)                              \
  template A                                                                        \
  type_info T A::RTTI_type_info(#T #A);                                             \
  template A                                                                        \
  type_info const& T A::RTTI_get_type_info() const                                  \
    { return RTTI_type_info; }                                                      \
  template A                                                                        \
  void* T A::RTTI_dynamic_cast(type_info const& info) const                         \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_3(A, T, B1, B2, B3)                          \
  template A                                                                        \
  type_info T A::RTTI_type_info(#T #A);                                             \
  template A                                                                        \
  type_info const& T A::RTTI_get_type_info() const                                  \
    { return RTTI_type_info; }                                                      \
  template A                                                                        \
  void* T A::RTTI_dynamic_cast(type_info const& info) const                         \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B3::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

#define RTTI_TEMPLATE_SCAFFOLDING_DEFN_4(A, T, B1, B2, B3, B4)                      \
  template A                                                                        \
  type_info T A::RTTI_type_info(#T #A);                                             \
  template A                                                                        \
  type_info const& T A::RTTI_get_type_info() const                                  \
    { return RTTI_type_info; }                                                      \
  template A                                                                        \
  void* T A::RTTI_dynamic_cast(type_info const& info) const                         \
    {                                                                               \
      if(&info == &RTTI_type_info)                                                  \
        return (void*)this;                                                         \
                                                                                    \
      void* b1;                                                                     \
      void* b2;                                                                     \
                                                                                    \
      b1 = B1::RTTI_dynamic_cast(info);                                             \
                                                                                    \
      b2 = B2::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B3::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      b2 = B4::RTTI_dynamic_cast(info);                                             \
      b1 = b1 ? b1 : b2;                                                            \
      if(b2 != 0 && b2 != b1)                                                       \
        return 0;                                                                   \
                                                                                    \
      return b1;                                                                    \
    }

#endif // BUILTIN_RTTI



class type_info
{
  public:

    virtual ~type_info();

    int operator==(type_info const&) const;
    int operator!=(type_info const&) const;
    int before(type_info const&) const;

    char const* name() const;

    // pretend that this is private
    type_info(char const* name);

    RTTI_SCAFFOLDING_DECL

  private:

    // not implemented
    type_info(type_info const&);
    type_info& operator=(type_info const&);

    char const* name_;
};

inline int type_info::operator!=(type_info const& rhs) const
  { return !(*this == rhs); }

inline int type_info::before(type_info const&) const
  { return (int)this; }

inline char const* type_info::name() const
  { return name_; }

#endif // cathlibcpp_ptypeinfo_H
